home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / ab20 / ab20_archive / utilities / emulators / spectrum_readplusd.lzh / ReadPlusD.mod < prev   
Text File  |  1991-04-25  |  13KB  |  462 lines

  1. MODULE ReadPlusD;
  2.  
  3. (*
  4.  
  5. This file may be distributed anywhere provided it is unmodified and is not
  6. sold for profit.  Please report bugs to the author.
  7.  
  8. Author: Peter McGavin, 86 Totara Crescent, Lower Hutt, New Zealand.
  9.         e-mail: srwmpnm@wnv.dsir.govt.nz .
  10.  
  11.  
  12. This Benchmark Modula-2 program reads an MGT (Miles Gordon Technology) PLUS D
  13. 3.5" double-sided diskette on any Amiga.  MGT PLUS D diskettes are used on
  14. Sinclair Spectrum computers.  This is useful for transferring Spectrum programs
  15. to the format required by the Spectrum emulator on the Amiga.
  16.  
  17. ReadPlusD requires messydisk.device (supplied with MSH on Fred Fish disk 382)
  18. in the devs: directory.
  19.  
  20.  
  21. CLI usage:   ReadPlusD disk-unit-number [directory-entry-number output-file]
  22.  
  23.  
  24. The disk unit number should be an integer in the range 0..3 corresponding to
  25. the drive (DF0:..DF3:) containing the PLUS D diskette.
  26.  
  27. If given just the unit-number, ReadPlusD displays a directory of the disk.
  28.  
  29. If you also give a directory entry number and an output file name, ReadPlusD
  30. converts a 48 kbyte snapshot file to the format required by the Amiga Spectrum
  31. emulator.  The output is written to the given file name.
  32.  
  33. Note that you specify the number of the directory entry (an integer in the
  34. range 1..80), not the name of the input file.  If the file is not a 48 kbyte
  35. snapshot file, ReadPlusD displays an error message.
  36.  
  37.  
  38. Examples:
  39.  
  40. ReadPlusD 2            get a directory of the PLUS D disk in DF2:
  41.  
  42. ReadPlusD 1 17 RAM:TRON        convert the 17th file on DF1: to RAM:TRON
  43.  
  44.  
  45. Known bug:
  46.  
  47. ReadPlusD always sets the z80 interrupt mode to 1.  A few Spectrum programs use
  48. interrupt mode 2.  If a converted program doesn't run and you suspect it might
  49. use mode 2, try patching the byte at offset 25 in the output file to be $02.
  50. Use a binary file editor like, for example, NEWZAP.  The byte you patch is
  51. actually the 26th byte in the file (because the 1st byte is at offset 0), and
  52. it will always be $01 to begin with.
  53.  
  54. If you know how to fix this bug, please tell me how to do it.
  55.  
  56. *)
  57.  
  58. FROM SYSTEM IMPORT ADR, ADDRESS, BYTE, LONGWORD;
  59. FROM AmigaDOS IMPORT FileHandle, ModeNewFile, Open, Write, Close;
  60. FROM Conversions IMPORT ConvStringToNumber;
  61. FROM InOut IMPORT WriteLn, WriteString, WriteCard, Read;
  62. FROM IODevices IMPORT OpenDevice, CloseDevice, DoIO, CmdRead;
  63. FROM IODevicesUtil IMPORT CreateExtIO, DeleteExtIO;
  64. FROM Memory IMPORT AllocMem, FreeMem, MemReqSet, MemPublic, MemClear;
  65. FROM Ports IMPORT MsgPortPtr, GetMsg, PutMsg, WaitPort;
  66. FROM PortsUtil IMPORT CreatePort, DeletePort;
  67. FROM Strings IMPORT ExtractSubString;
  68. FROM System IMPORT argc, argv;
  69. FROM TrackDiskDevice IMPORT IOExtTD, IOExtTDPtr, TDName, TDMotor;
  70.  
  71.  
  72. CONST
  73.   MDName = "messydisk.device";
  74.   NumSecs = 10;
  75.  
  76.  
  77. VAR
  78.   buffer: ARRAY [0..511] OF BYTE;
  79.  
  80.  
  81. PROCEDURE motor (diskreq: IOExtTDPtr; onoff: BOOLEAN);
  82. VAR
  83.   dummy: LONGINT;
  84. BEGIN
  85.   WITH diskreq^.iotdReq DO
  86.     IF onoff THEN
  87.       ioLength := 1D
  88.     ELSE
  89.       ioLength := 0D
  90.     END;
  91.     ioCommand := TDMotor
  92.   END;
  93.   dummy := DoIO (diskreq)
  94. END motor;
  95.  
  96.  
  97. PROCEDURE read_sector (diskreq: IOExtTDPtr;
  98.                        sector: CARDINAL;
  99.                        bufptr: ADDRESS): CARDINAL;
  100. VAR
  101.   dummy: LONGINT;
  102. BEGIN
  103.   WITH diskreq^.iotdReq DO
  104.     ioLength := 512D;
  105.     ioData := bufptr;
  106.     ioOffset := 512D * LONGCARD(sector);
  107.     ioCommand := CmdRead;
  108.     dummy := DoIO (diskreq);
  109.     RETURN CARDINAL (ioError)
  110.   END
  111. END read_sector;
  112.  
  113.  
  114. PROCEDURE msh_sector (track, sector: CARDINAL): CARDINAL;
  115. (* Convert from Plus-D track and sector number to messydisk sector number *)
  116. BEGIN
  117.   IF track >= 128 THEN            (* it's on the reverse side *)
  118.     RETURN 2 * NumSecs * (track - 128) + NumSecs + sector - 1
  119.   ELSE
  120.     RETURN 2 * NumSecs * track + sector - 1
  121.   END
  122. END msh_sector;
  123.  
  124.  
  125. TYPE
  126.   dir_entry_type = RECORD
  127.     CASE :INTEGER OF
  128.       0: c: ARRAY [0..255] OF CHAR |
  129.       1: b: ARRAY [0..255] OF BYTE
  130.     END;
  131.   END;
  132.  
  133.   dir_entry_ptr_type = POINTER TO dir_entry_type;
  134.  
  135.  
  136. PROCEDURE write_dir_entry (entry_number: CARDINAL;
  137.                            dir_entry_ptr: dir_entry_ptr_type);
  138. VAR
  139.   name: ARRAY [0..10] OF CHAR;
  140. BEGIN
  141.   WITH dir_entry_ptr^ DO
  142.     IF CARDINAL(b[0]) <> 0 THEN
  143.       WriteCard (entry_number, 2);
  144.       WriteString ("  ");
  145.       CASE CARDINAL(b[0]) OF
  146.         1: WriteString ("Basic program    ") |
  147.         2: WriteString ("Numeric array    ") |
  148.         3: WriteString ("Character array  ") |
  149.         4: WriteString ("Code file        ") |
  150.         5: WriteString ("48k snapshot     ") |
  151.         7: WriteString ("Screen dump      ") |
  152.         10:WriteString ("Open# file       ")
  153.       ELSE
  154.         WriteString ("Type ");
  155.         WriteCard (CARDINAL(b[0]), 2);
  156.         WriteString ("          ")
  157.       END;
  158.       ExtractSubString (name, c, 1, 10);
  159.       WriteString (name);
  160.       WriteCard (CARDINAL(b[12]), 6);    (* size *)
  161. (*
  162.       WriteCard (CARDINAL(b[13]), 4);    (* starting track *)
  163.       WriteCard (CARDINAL(b[14]), 4);    (* starting sector *)
  164. *)
  165.       WriteLn
  166.     END
  167.   END
  168. END write_dir_entry;
  169.  
  170.  
  171. PROCEDURE directory (diskreq: IOExtTDPtr): BOOLEAN;
  172. VAR
  173.   track,
  174.   sector,
  175.   entry_number: CARDINAL;
  176. BEGIN
  177.   entry_number := 0;
  178.   FOR track := 0 TO 3 DO
  179.     FOR sector := 1 TO 10 DO
  180.       IF read_sector (diskreq, msh_sector (track, sector), ADR(buffer)) <> 0 THEN
  181.         WriteString ("Error reading sector\n");
  182.         RETURN FALSE
  183.       END;
  184.       INC (entry_number);
  185.       write_dir_entry (entry_number, ADR(buffer[0]));
  186.       INC (entry_number);
  187.       write_dir_entry (entry_number, ADR(buffer[256]))
  188.     END
  189.   END;
  190.   RETURN TRUE
  191. END directory;
  192.  
  193.  
  194. PROCEDURE convert_snapshot (entry_number: CARDINAL;
  195.                             filename: ARRAY OF CHAR;
  196.                             diskreq: IOExtTDPtr): BOOLEAN;
  197. CONST
  198.   image_size = 49179D;
  199.   image_buffer_size = image_size + 512D;
  200. VAR
  201.   track,
  202.   sector,
  203.   sp: CARDINAL;
  204.   z80_address,
  205.   tmp: LONGCARD;
  206.   ok: BOOLEAN;
  207.   image: POINTER TO ARRAY [0..27] OF BYTE;   (* really 49179 byte buffer *)
  208.   image_ptr: POINTER TO ARRAY [0..511] OF BYTE;
  209.   dir_entry_ptr: dir_entry_ptr_type;
  210.   file: FileHandle;
  211. BEGIN
  212.   ok := TRUE;
  213.   image := NIL;
  214.   file := NIL;
  215.  
  216.   IF (entry_number <= 0) OR (entry_number > 80) THEN
  217.     WriteString ("Entry number is out of range\n");
  218.     ok := FALSE
  219.   END;
  220.  
  221.   DEC (entry_number);    (* now in range 0..79 *)
  222.  
  223.   IF ok THEN
  224.     track := entry_number DIV 20;
  225.     sector := (entry_number MOD 20) DIV 2 + 1;
  226.     IF read_sector (diskreq, msh_sector (track, sector), ADR(buffer)) <> 0 THEN
  227.       WriteString ("Error reading sector\n");
  228.       ok := FALSE
  229.     END
  230.   END;
  231.  
  232.   IF ok THEN
  233.     IF ODD(entry_number) THEN
  234.       dir_entry_ptr := ADR(buffer[256])
  235.     ELSE
  236.       dir_entry_ptr := ADR(buffer[0])
  237.     END;
  238.     WITH dir_entry_ptr^ DO
  239.       IF CARDINAL(b[0]) <> 5 THEN
  240.         WriteString ("Error, entry number ");
  241.         WriteCard (entry_number + 1, 2);
  242.         WriteString (" is not a 48k snapshot file\n");
  243.         ok := FALSE
  244.       END
  245.     END
  246.   END;
  247.  
  248.   IF ok THEN
  249.     image := AllocMem (image_buffer_size, MemReqSet{});
  250.     IF image = NIL THEN
  251.       WriteString ("Can't allocate image buffer\n");
  252.       ok := FALSE
  253.     END
  254.   END;
  255.  
  256.   IF ok THEN
  257.     sp := 256 * CARDINAL(dir_entry_ptr^.b[0F1H]) + CARDINAL(dir_entry_ptr^.b[0F0H]);
  258.     INC (sp, 4);
  259.     image^[ 0] := dir_entry_ptr^.b[0EFH];    (* i    *)
  260.     image^[ 1] := dir_entry_ptr^.b[0E4H];    (* l'    *)
  261.     image^[ 2] := dir_entry_ptr^.b[0E5H];    (* h'    *)
  262.     image^[ 3] := dir_entry_ptr^.b[0E0H];    (* e'    *)
  263.     image^[ 4] := dir_entry_ptr^.b[0E1H];    (* d'    *)
  264.     image^[ 5] := dir_entry_ptr^.b[0E2H];    (* c'    *)
  265.     image^[ 6] := dir_entry_ptr^.b[0E3H];    (* b'    *)
  266.     image^[ 7] := dir_entry_ptr^.b[0E6H];    (* f'    *)
  267.     image^[ 8] := dir_entry_ptr^.b[0E7H];    (* a'    *)
  268.     image^[ 9] := dir_entry_ptr^.b[0ECH];    (* l    *)
  269.     image^[10] := dir_entry_ptr^.b[0EDH];    (* h    *)
  270.     image^[11] := dir_entry_ptr^.b[0E8H];    (* e    *)
  271.     image^[12] := dir_entry_ptr^.b[0E9H];    (* d    *)
  272.     image^[13] := dir_entry_ptr^.b[0EAH];    (* c    *)
  273.     image^[14] := dir_entry_ptr^.b[0EBH];    (* b    *)
  274.     image^[15] := dir_entry_ptr^.b[0DCH];    (* iyl    *)
  275.     image^[16] := dir_entry_ptr^.b[0DDH];    (* iyh    *)
  276.     image^[17] := dir_entry_ptr^.b[0DEH];    (* ixl    *)
  277.     image^[18] := dir_entry_ptr^.b[0DFH];    (* ixh    *)
  278.     image^[19] := dir_entry_ptr^.b[0EEH];    (* int    *)
  279.     image^[20] := BYTE(00H);            (* r    *)
  280.     image^[21] := BYTE(00H);            (* f    filled in later *)
  281.     image^[22] := BYTE(00H);            (* a    filled in later *)
  282.     image^[23] := BYTE(sp MOD 256);        (* spl    *)
  283.     image^[24] := BYTE(sp DIV 256);        (* sph    *)
  284.     image^[25] := BYTE(1);            (* im    might be wrong!!! *)
  285.     image^[26] := BYTE(0);            (* fill    *)
  286.     track := CARDINAL(dir_entry_ptr^.b[00DH]);
  287.     sector := CARDINAL(dir_entry_ptr^.b[00EH]);
  288.     image_ptr := ADR(image^[27]);
  289.     z80_address := 16384D
  290.   END;
  291.  
  292.   WHILE ok AND (track <> 0) AND (sector <> 0) DO
  293.     IF read_sector (diskreq, msh_sector (track, sector), image_ptr) <> 0 THEN
  294.       WriteString ("Error reading sector\n");
  295.       ok := FALSE
  296.     ELSE
  297.       tmp := LONGCARD(sp - 2);
  298.       IF (tmp >= z80_address) AND
  299.          (tmp < (z80_address + 510D)) THEN
  300.         image^[21] := image_ptr^[CARDINAL(tmp - z80_address)]    (* f    *)
  301.       END;
  302.       tmp := LONGCARD(sp - 1);
  303.       IF (tmp >= z80_address) AND
  304.          (tmp < (z80_address + 510D)) THEN
  305.         image^[22] := image_ptr^[CARDINAL(tmp - z80_address)]    (* a    *)
  306.       END;
  307.       track := CARDINAL(image_ptr^[510]);
  308.       sector := CARDINAL(image_ptr^[511]);
  309.       image_ptr := ADDRESS(LONGCARD(image_ptr) + 510D);
  310.       INC (z80_address, 510D)
  311.     END
  312.   END;
  313.  
  314.   IF ok THEN
  315.     file := Open (ADR(filename), ModeNewFile);
  316.     IF file = NIL THEN
  317.       WriteString ("Error opening output file\n");
  318.       ok := FALSE
  319.     END
  320.   END;
  321.  
  322.   IF ok THEN
  323.     IF Write (file, image, image_size) <> image_size THEN
  324.       WriteString ("Error writing output file\n");
  325.       ok := FALSE
  326.     END
  327.   END;
  328.  
  329.   IF file <> NIL THEN
  330.     Close (file)
  331.   END;
  332.  
  333.   IF image <> NIL THEN
  334.     FreeMem (image, image_buffer_size)
  335.   END;
  336.  
  337.   RETURN ok
  338. END convert_snapshot;
  339.  
  340.  
  341. VAR
  342.   unit: CARDINAL;
  343.   diskport: MsgPortPtr;
  344.   diskreq: IOExtTDPtr;
  345.   devopen: LONGINT;
  346.   ok: BOOLEAN;
  347.   ch: CHAR;
  348.   entry_number: CARDINAL;
  349.   temp: LONGCARD;
  350.  
  351. BEGIN
  352.   ok := TRUE;
  353.   diskport := NIL;
  354.   diskreq := NIL;
  355.   devopen := -1D;
  356.   unit := 0;
  357.   entry_number := 0;
  358.  
  359.   IF ok THEN
  360.     IF (argc <> 2) AND (argc <> 4) THEN
  361.       ok := FALSE
  362.     END
  363.   END;
  364.  
  365.   IF ok THEN
  366.     IF argc >= 2 THEN
  367.       ok := ConvStringToNumber (argv^[1]^, temp, FALSE, 10);
  368.       IF ok THEN
  369.         unit := CARDINAL(temp);
  370.         ok := unit < 4
  371.       END;
  372.       IF NOT ok THEN
  373.         WriteString ("Disk unit must be a number in the range 0..3\n")
  374.       END
  375.     END
  376.   END;
  377.  
  378.   IF ok THEN
  379.     IF argc >= 3 THEN
  380.       ok := ConvStringToNumber (argv^[2]^, temp, FALSE, 10);
  381.       IF ok THEN
  382.         entry_number := CARDINAL(temp);
  383.         ok := (entry_number > 0) AND (entry_number <= 80)
  384.       END;
  385.       IF NOT ok THEN
  386.         WriteString ("Entry number must be a number in the range 1..80\n")
  387.       END
  388.     END
  389.   END;
  390.  
  391.   IF NOT ok THEN
  392.     WriteString ("Usage: ReadPlusD disk-unit-number [entry-number output-file]\n");
  393.   END;
  394.  
  395.   IF ok THEN
  396.     diskport := CreatePort (NIL, 0);
  397.     IF diskport = NIL THEN
  398.       WriteString ("Can't create message port\n");
  399.       ok := FALSE
  400.     END
  401.   END;
  402.  
  403.   IF ok THEN
  404.     diskreq := CreateExtIO (diskport^, SIZE(IOExtTD));
  405.     IF diskreq = NIL THEN
  406.       WriteString ("Can't create external IO request\n");
  407.       ok := FALSE
  408.     END
  409.   END;
  410.  
  411.   IF ok THEN
  412.     devopen := OpenDevice (ADR(MDName), unit, diskreq, 0D);
  413.     IF devopen <> 0D THEN
  414.       WriteString ("Can't open devs:messydisk.device on unit ");
  415.       WriteCard (unit, 1);
  416.       WriteLn;
  417.       ok := FALSE
  418.     END
  419.   END;
  420.  
  421.   IF ok THEN (* must read sector 0 first to discover number of sectors/track *)
  422.     ok := read_sector (diskreq, 0, ADR(buffer)) = 0;
  423.     IF NOT ok THEN
  424.       WriteString ("Error reading sector\n")
  425.     END
  426.   END;
  427.  
  428.   IF ok THEN
  429.     IF entry_number = 0 THEN
  430.       ok := directory (diskreq)
  431.     END
  432.   END;
  433.  
  434.   IF ok THEN
  435.     IF entry_number <> 0 THEN
  436.       WriteString ("\nConverting entry ");
  437.       WriteCard (entry_number, 1);
  438.       WriteString (" to ");
  439.       WriteString (argv^[3]^);
  440.       WriteLn;
  441.       ok := convert_snapshot (entry_number, argv^[3]^, diskreq)
  442.     END
  443.   END;
  444.  
  445.   IF devopen = 0D THEN
  446.     motor (diskreq, FALSE);
  447.     CloseDevice (diskreq);
  448.     devopen := -1D
  449.   END;
  450.  
  451.   IF diskreq <> NIL THEN
  452.     DeleteExtIO (diskreq);
  453.     diskreq := NIL
  454.   END;
  455.  
  456.   IF diskport <> NIL THEN
  457.     DeletePort (diskport^);
  458.     diskport := NIL
  459.   END
  460.  
  461. END ReadPlusD.
  462.